home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / prospero / propsero.lha / prospero-beta.4.2e / server / dirsrv.c next >
C/C++ Source or Header  |  1992-02-10  |  62KB  |  2,119 lines

  1. /*
  2.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  3.  *
  4.  * For copying and distribution information, please see the file
  5.  * <uw-copyright.h>.
  6.  */
  7.  
  8. #include <uw-copyright.h>
  9.  
  10. #include <netdb.h>
  11. #include <sgtty.h>
  12. #include <signal.h>
  13. #include <stdio.h>
  14. #include <strings.h>
  15. #include <sys/file.h>
  16. #include <sys/ioctl.h>
  17. #include <sys/param.h>
  18. #include <sys/socket.h>
  19. #include <sys/time.h>
  20.  
  21. #include <pfs.h>
  22. #include <psite.h>
  23. #include <plog.h>
  24. #include <pauthent.h>
  25. #include <pprot.h>
  26. #include <perrno.h>
  27. #include <pmachine.h>
  28.  
  29. #include "dirsrv.h"
  30.  
  31. #ifndef P_RUNDIR
  32. #define P_RUNDIR    "/tmp"
  33. #endif
  34.  
  35. #define THREAD_COUNT    4
  36.  
  37. extern int errno;
  38.  
  39. extern char    *acltypes[];
  40.  
  41. /* To check for memory leaks */
  42. extern int vlink_count;
  43. extern int pattrib_count;
  44. extern int acl_count;
  45. extern int pfile_count;
  46. extern int preq_count;
  47. extern int ptext_count;
  48. extern int string_count;
  49. extern int vlink_max;
  50. extern int pattrib_max;
  51. extern int acl_max;
  52. extern int pfile_max;
  53. extern int preq_max;
  54. extern int ptext_max;
  55. extern int string_max;
  56.  
  57. extern int pQlen;
  58.  
  59. static    cmd_lookup();
  60. VLINK    check_fwd();
  61. char    *month_sname();
  62. char    *check_nfs();
  63.  
  64. static char            prog[40];
  65. static int         fault_count = 0;
  66. static char        last_request[MAX_PTXT_LEN] = "";
  67. static char        *last_error = NULL;
  68. static char        st_time_str[40];
  69.  
  70. static int        in_port = -1;
  71. static char        *in_parg = "-p-1";
  72.  
  73. static int        req_count = 0;
  74. static int        crdir_count = 0;
  75. static int        crlnk_count = 0;
  76. static int        crobj_count = 0;
  77. static int        dellnk_count = 0;
  78. static int        eoi_count = 0;
  79. static int        goi_count = 0;
  80. static int        list_count = 0;
  81. static int        lacl_count = 0;
  82. static int        modl_count = 0;
  83. static int        macl_count = 0;
  84. static int        status_count = 0;
  85. static int        upddir_count = 0;
  86. int            oldform_count = 0;
  87.  
  88. char    shadow[MAXPATHLEN]    = P_FSHADOW;
  89. char    pfsdat[MAXPATHLEN]    = P_FSTORAGE;
  90. char    dirshadow[MAXPATHLEN] = DSHADOW;
  91. char    dircont[MAXPATHLEN]   = DCONTENTS;
  92.  
  93. #ifdef ARCHIE
  94. extern int     prioritize_request();
  95. #endif 
  96.  
  97. #ifdef PSRV_ROOT
  98. char    root[MAXPATHLEN]      = PSRV_ROOT;
  99. #else
  100. char    root[MAXPATHLEN]      = "";
  101. #endif
  102.  
  103. #ifdef AFTPDIRECTORY
  104. char    aftpdir[MAXPATHLEN]   = AFTPDIRECTORY;
  105. #else
  106. char    aftpdir[MAXPATHLEN]   = "";
  107. #endif
  108.  
  109. #ifdef AFSDIRECTORY
  110. char    afsdir[MAXPATHLEN]    = AFSDIRECTORY;
  111. #else
  112. char    afsdir[MAXPATHLEN]    = "";
  113. #endif
  114.  
  115. #ifdef DATABASE_PREFIX
  116. char    *db_prefix            = DATABASE_PREFIX;
  117. #else
  118. char    *db_prefix            = "";
  119. #endif
  120.  
  121. char    hostname[MAXPATHLEN]  = "";    /* Server's host name                */
  122. char    hostwport[MAXPATHLEN+30] = ""; /* Host name w/ port if non-standard */
  123.  
  124. int     f;
  125.  
  126. main(argc, argv)
  127.     int     argc;
  128.     char   *argv[];
  129.     {
  130.     int             mflag = 0;       /* Manual start of server */
  131.     int             on = 1;
  132.  
  133.     struct sockaddr_in     from;
  134.     int            port_no;
  135.     struct hostent        *current_host;
  136.     int             fromlen;
  137.     PTEXT           pkt;
  138.     PREQ            curr_req;
  139.     register int        n;
  140.     int             child;
  141.     int            retval;
  142.  
  143.     long             now;
  144.     struct tm         *tm;
  145.  
  146.     strcpy(prog,argv[0]);
  147.     
  148.     umask(0);
  149.     
  150.     /* If first arg is "-m" then continue to run */
  151.     /* from this terminal.                */
  152.     if (argc > 1 && !strcmp(argv[1],"-m")) {
  153.         mflag++;
  154.         argc--;
  155.         argv++;
  156.     }
  157.     
  158.     /* If first arg is "-p#" then privileged UDP port already open   */
  159.     /* Note: Eventually, this will treat a number as an FD, a string */
  160.     /* following the -p as a name to look up in /etc/services and a  */
  161.     /* number preceded by a # as a port number.  In the latter two   */
  162.     /* cases, bind port would be called.  For now, however, bind     */
  163.     /* port must be called in addition to any port that is passed    */
  164.     if (argc > 1 && !strncmp(argv[1],"-p",2)) {
  165.         in_parg = argv[1];
  166.         sscanf(argv[1],"-p%d",&in_port);
  167.         set_prvport(in_port);
  168.         argc--;
  169.         argv++;
  170.     }
  171.  
  172.     /* If first arg is "-F" then set fault count from next argument */
  173.     if (argc > 1 && !strncmp(argv[1],"-F",2)) {
  174.         fault_count = -1;
  175.         sscanf(argv[1],"-F%d",&fault_count);
  176.         argc--;
  177.         argv++;
  178.  
  179.     }
  180.  
  181.     /* If first arg is "-E" then set last_error */
  182.     if (argc > 1 && !strncmp(argv[1],"-E",2)) {
  183.         last_error = argv[1]+2;
  184.         argc--;
  185.         argv++;
  186.     }
  187.  
  188.     /* usage */
  189.     if ((argc > 7) || (argc > 1 && !strcmp(argv[1],"-h"))) {
  190.         fprintf(stderr,
  191.             "Usage: dirsrv [-m] root shadow data aftp afs hostname\n");
  192.         exit(1);
  193.     }
  194.     
  195.     if ((argc > 1) && *(argv[1]))
  196.         strcpy(root,argv[1]);
  197.     
  198.     if ((argc > 2) && *(argv[2]))
  199.         strcpy(shadow,argv[2]);
  200.     
  201.     if ((argc > 3) && *(argv[3]))
  202.         strcpy(pfsdat,argv[3]);
  203.     
  204.     if ((argc > 4) && *(argv[4]))
  205.         strcpy(aftpdir,argv[4]);
  206.     
  207.     if ((argc > 5) && *(argv[5]))
  208.         strcpy(afsdir,argv[5]);
  209.     
  210.     if ((argc > 6) && *(argv[6]))
  211.         strcpy(hostname,argv[6]);
  212.     
  213.     /* Here we should really get the host name in cannonical form */
  214.     
  215.     if(*hostname == '\0') {
  216. #ifndef PSRV_HOSTNAME
  217.         strncpy(hostname,myhostname(),sizeof(hostname));
  218. #else
  219.         strncpy(hostname,PSRV_HOSTNAME,sizeof(hostname));
  220. #endif PSRV_HOSTNAME
  221.     }
  222.     
  223.     ucase(hostname);
  224.     
  225.     /* Note our start time */
  226.     (void) time(&now);
  227.     tm = gmtime(&now);
  228.     sprintf(st_time_str,"%2d-%s-%02d %02d:%02d:%02d UTC",tm->tm_mday,
  229.          month_sname(tm->tm_mon + 1),tm->tm_year,
  230.          tm->tm_hour, tm->tm_min, tm->tm_sec);
  231.  
  232.     retval = chdir(P_RUNDIR);
  233.     
  234.     if(retval) plog(L_STATUS,NULL,NULL,"Startup - chdir failed: %d",errno,0);
  235.     
  236.     /* Eventually, we will only set up and bind a port if one    */
  237.     /* wasn't already passed to us using the -p option.  Until   */
  238.     /* all clients can support alternative ports, however, we    */
  239.     /* must bind the DIRSRV port in addition to any that were    */
  240.     /* passed to us.  Note that at this point, unless we are     */
  241.     /* running as root (which we should not be) we would not     */
  242.     /* have been able to bind the priveleged port.               */
  243.  
  244.     port_no = bind_port("dirsrv");
  245.     
  246. #ifdef TAG_UNASSIGNED_PORT
  247.     if((in_port < 0) && (port_no != PROSPERO_PORT)) 
  248.         sprintf(hostwport,"%s(%d)",hostname,port_no);
  249.     else
  250. #endif 
  251.         strcpy(hostwport,hostname);
  252.  
  253. #ifdef ARCHIE
  254.     /* Set queueing policy */
  255.     set_queuing_policy(prioritize_request,0);
  256. #endif /* ARCHIE */
  257.  
  258.     if (!mflag) {
  259.         if ((child = fork()) != 0) {
  260.         printf("%s started, PID=%d, PORT=%d\n", 
  261.                prog, child, port_no);
  262.         exit(0);
  263.         }
  264.         setup_disc();
  265.     }
  266.     else printf("%s started, PORT=%d\n", prog, port_no);
  267.     
  268.     plog(L_STATUS,NULL,NULL,"Startup - Mode: %s, Root: %s, Shadow: %s, Aftpdir: %s, Host: %s", 
  269.          (mflag ? "manual" : "server"),root,shadow,aftpdir,hostwport,0);
  270.     
  271.     /* set dirsend timeout for chasing forwarding pointers */
  272.     set_dirsend_retry(4,1);
  273.     
  274.  
  275. #ifndef THREADS
  276.     /* receive loop */
  277.     for (;;) {
  278.         curr_req = get_next_request();
  279.         pkt = curr_req->recv;
  280. #ifdef DEBUG        
  281.         strcpy(last_request,pkt->start); /* For error logging */
  282. #endif DEBUG
  283.         req_count++;
  284.         dirsrv(curr_req, pkt);
  285.     }    
  286. #else /* THREADS */
  287.     /* receive loop */
  288.     for (;;) {
  289.         int        free_count = THREAD_COUNT;
  290.  
  291.         if(threadcount > 0) {
  292.         curr_req = get_next_request();
  293.         pkt = curr_req->recv;
  294. #ifdef DEBUG        
  295.         strcpy(last_request,pkt->start); /* For error logging */
  296. #endif DEBUG
  297.         req_count++;
  298.         free_count--;
  299.         dirsrv(curr_req, pkt);
  300.         }
  301.         else {
  302.         free_count++;
  303.         }
  304.     }    
  305. #endif
  306.     }
  307.     
  308.     
  309. dirsrv(req, pkt)
  310.     PREQ req;
  311.     PTEXT   pkt;
  312.     {
  313.     static long     client_host;
  314. #ifdef DATABASE_PREFIX
  315.     static ACL    database_acl;
  316.     static int    dbacl_read = 0;
  317. #endif DATABASE_PREFIX
  318.  
  319.     /* The following are set in one line and used by subsequent */
  320.     /* lines of the same message                                */
  321.  
  322.     int    client_version = MAX_VERSION;   /* Protocol version nbr   */
  323.     char    auth_type[40];              /* Type of Authentication */
  324.     char    authent[160];               /* Authentication data    */
  325.     char    client_id[160];             /* Authenticated username */
  326.     char    client_dir[MAXPATHLEN];     /* Current directory      */
  327.     long    dir_version = -1;           /* Directory version nbr  */
  328.     long    dir_magic_no = -1;          /* Directory magic number */
  329. #ifdef ARCHIE
  330.     int    max_list_commands = 5;        /* Max lists in request   */
  331. #endif /* ARCHIE */
  332.  
  333.     CINFO_ST    id_st;
  334.     CINFO        id = & id_st;
  335.  
  336.     /* The following are used while processing the current line       */
  337.  
  338.     char        *command;          /* The current line            */
  339.     char        *command_next = NULL; /* The next line            */
  340.     int        cmd_code;          /* Operation code              */
  341.  
  342.     VDIR_ST        dir_st;            /* Directory contents used ... */
  343.     VDIR        dir = &dir_st;     /* by individual lines         */
  344.  
  345.     PFILE        fi;                /* individual lines            */
  346.  
  347.     VLINK        fl;                /* List of forwarding pointers */
  348.     VLINK        fp;                /* The current fp              */
  349.     
  350.     char        *components;       /* Components to be processed  */
  351.     char        *remcomp;       /* Remaining components        */
  352.     char        localexp;       /* OK to exp ul for remcomp    */
  353.     VLINK        uexp;           /* Current link being expanded */
  354.     char        attribfl;       /* Send back atribues in list  */
  355.     int        item_count = 0;    /* Count of returned items     */
  356.  
  357.     /* Temporaries */
  358.  
  359.     char        dir_type[40];     /* Type or dir name (ASCII)     */
  360.     char        *amarg;           /* Arguments for access method  */
  361.     VLINK        clink;            /* For stepping through links   */
  362.     VLINK        crep;            /* For stepping through replicas*/
  363.     VLINK        cfil;             /* For stepping through filters */
  364.     PATTRIB        ca;          /* Current Attribute            */
  365.  
  366.     char        *suffix;      /* Trailing component(s)        */
  367.     int        rsinfo_ret;       /* Ret Val from dsrfinfo        */
  368.     int        verify_dir;       /* Only verifying the directory */
  369.     int        retval;
  370.     int        tmp;
  371.  
  372.     int        lpriv;          /* LPRIV option for CREATE-DIR  */
  373.     ACL        wacl;          /* Working access control list  */
  374.     int        laclchkl;         /* Cached ACL check             */
  375.     int        daclchkl;         /* Cached ACL check             */
  376.     int        laclchkr;         /* Cached ACL check             */
  377.     int        daclchkr;         /* Cached ACL check             */
  378.     int        aclchk;              /* Cached ACL check             */
  379.     ACL        nacl;          /* New ACL entry                */
  380.  
  381.     /* Temporaries for use by sscanf */
  382.     char    t_ltype;
  383.     char     t_name[MAX_DIR_LINESIZE];
  384.     char    t_type[MAX_DIR_LINESIZE];
  385.     char     t_htype[MAX_DIR_LINESIZE];
  386.     char     t_host[MAX_DIR_LINESIZE];
  387.     char     t_ntype[MAX_DIR_LINESIZE];
  388.     char     t_fname[MAX_DIR_LINESIZE];
  389.     char     t_args[MAX_DIR_LINESIZE];
  390.     char    t_options[MAX_DIR_LINESIZE];
  391.     char     t_acetype[MAX_DIR_LINESIZE];
  392.     char     t_atype[MAX_DIR_LINESIZE];
  393.     char     t_rights[MAX_DIR_LINESIZE];
  394.     char    t_principals[MAX_DIR_LINESIZE];
  395.     int    t_num;
  396.     int    n_options;
  397.  
  398.     char    insrights[MAX_DIR_LINESIZE];
  399.  
  400.     char    qatype[MAX_DIR_LINESIZE];
  401.     char    qrights[MAX_DIR_LINESIZE];
  402.  
  403.     vdir_init(dir);
  404.  
  405. #ifdef DATABASE_PREFIX
  406.     if(!dbacl_read++) {
  407.         retval = dsrdir(DATABASE_PREFIX,0,dir,NULL,0);
  408.         if(!retval) database_acl = dir->dacl;
  409.         else aclfree(dir->dacl); 
  410.         dir->dacl = NULL;
  411.         vllfree(dir->links); dir->links = NULL;
  412.         vllfree(dir->ulinks); dir->ulinks = NULL;
  413.     }
  414. #endif DATABASE_PREFIX
  415.  
  416.     id->ainfo_type = 0;
  417.     id->authenticator = NULL;
  418.     id->userid = NULL;
  419.     bcopy(&(req->fromto.sin_addr),&(id->haddr),sizeof(id->haddr));
  420.     id->port = ntohs(req->fromto.sin_port);
  421.     id->previous = NULL;
  422.     id->next = NULL;
  423.     
  424.     client_host = req->fromto.sin_addr.s_addr;
  425.  
  426.     *client_dir = '\0';
  427.     strcpy(authent,"NONE");
  428.     strcpy(client_id,"");
  429.     
  430.     command_next = pkt->start;
  431.     get_token(command,'\n');       /* Defined in pprot.h */
  432.     
  433.     while(command)     {
  434.         
  435.         cmd_code = cmd_lookup(command);
  436.         switch(cmd_code) {
  437.         
  438.         case STATUS:
  439.         status_count++;
  440.         replyf(req,"Prospero server (%s) %s",PFS_RELEASE,hostwport,0);
  441.         if(fault_count) 
  442.             replyf(req,"Faults since startup %d",fault_count,0);
  443.         replyf(req,"Requests since startup %d (%d+%d+%d %d+%d+%d %d %d+%d+%d %d %d)%s",
  444.                req_count, list_count, goi_count, lacl_count, 
  445.                crlnk_count, crdir_count, crobj_count, dellnk_count, 
  446.                modl_count, eoi_count, macl_count, upddir_count,
  447.                status_count, (oldform_count ? " OF" : ""), 0);
  448.         replyf(req,"Started: %s",st_time_str,0);
  449. #ifdef PROSPERO_CONTACT
  450.         replyf(req,"Contact: %s",PROSPERO_CONTACT,0);
  451. #endif PROSPERO_CONTACT
  452.         replyf(req," Memory: %d(%d)vl %d(%d)at %d(%d)acl %d(%d)fi %d(%d)pr %d(%d)pt %d(%d)str",
  453.                vlink_count,vlink_max,pattrib_count,pattrib_max,
  454.                acl_count,acl_max,pfile_count,pfile_max,preq_count,
  455.                preq_max,ptext_count,ptext_max,
  456.                string_count,string_max,0);
  457. #ifndef PSRV_READ_ONLY
  458.         if(*pfsdat) replyf(req,"   Data: %s", pfsdat, 0);
  459. #endif PSRV_READ_ONLY
  460.         if(*root) replyf(req,"   Root: %s", root, 0);
  461.         if(*aftpdir) replyf(req,"   AFTP: %s", aftpdir, 0);
  462.         if(*afsdir) replyf(req,"    AFS: %s", afsdir, 0);
  463.         if(*db_prefix) replyf(req,"     DB: %s", db_prefix, 0);
  464.         if(last_error) replyf(req,"  Error: %s",last_error,0);
  465.  
  466.         plog(L_DIR_PINFO, client_host, client_id, "STATUS Request",0);
  467.         break;
  468.  
  469.         case VERSION:
  470.         tmp = sscanf(command,"VERSION %d",&client_version);
  471.         if(tmp != 1) {
  472.             replyf(req,"VERSION %d (%s)",MAX_VERSION,PFS_RELEASE,0);
  473.             break;
  474.         }
  475.         if(client_version == MAX_VERSION) break;
  476.         if((client_version < MAX_VERSION) && 
  477.            (client_version >= MIN_VERSION)) {
  478.             plog(L_DIR_PWARN,client_host,NULL,"Old version in use: %d",
  479.              client_version, 0);
  480.             break;
  481.         }
  482.         if(MAX_VERSION == MIN_VERSION)
  483.             sendmf(req,"VERSION-NOT-SUPPORTED TRY %d",MAX_VERSION, 0);
  484.         else sendmf(req,"VERSION-NOT-SUPPORTED TRY %d-%d",
  485.                 MIN_VERSION,MAX_VERSION, 0);
  486.         plog(L_DIR_PERR,client_host,NULL,"Unimplemented version in use: %d",
  487.              client_version, 0);
  488.         return(PFAILURE);
  489.         break;
  490.         
  491.         case AUTHENTICATOR:
  492.         tmp = sscanf(command,"AUTHENTICATOR %s %s",auth_type,authent);
  493.         if(tmp != 2) {
  494.             sendmf(req,"ERROR Invalid arguments: %s",command, 0);
  495.             plog(L_DIR_PERR, client_host, NULL,
  496.              "Invalid AUTHENTICATOR command: %s", command, 0);
  497.             return(PFAILURE);
  498.         }
  499.         if(strcmp(auth_type,"UNAUTHENTICATED")) {
  500.             sendmf(req,"ERROR authentication type %s not supported",
  501.                auth_type,0);
  502.             plog(L_DIR_ERR,client_host,NULL,"Invalid auth-type %s: %s", 
  503.              auth_type,command,0);
  504.             return(PFAILURE);
  505.         }
  506.         strcpy(client_id,authent);
  507.  
  508.         id->userid = client_id;
  509.         id->auth_type = auth_type;
  510.         id->authenticator = authent;
  511.  
  512.         break;
  513.         
  514.         case DIRECTORY:
  515.         dir_version = 0;
  516.         dir_magic_no = 0;
  517.         tmp = sscanf(command,"DIRECTORY %s %s %d %d",
  518.                  dir_type,client_dir,&dir_version,&dir_magic_no);
  519.         
  520.         if(tmp < 2) {
  521.             sendmf(req,"ERROR Invalid arguments: %s",command, 0);
  522.             plog(L_DIR_PERR,client_host,client_id,
  523.              "Invalid DIRECTORY command: %s",command,0);
  524.             return(PFAILURE);
  525.         }
  526.         
  527.         if(strcmp(dir_type,"ASCII")) {
  528.             sendmf(req,"ERROR id-type %s not supported",dir_type,0);
  529.             plog(L_DIR_ERR,client_host,client_id,"Invalid id-type: %s",
  530.              command, 0);
  531.             return(PFAILURE);
  532.         }
  533.         
  534.         if(check_path(client_dir) == FALSE) {
  535.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  536.             plog(L_AUTH_ERR,client_host,client_id,
  537.              "Invalid directory name: %s",client_dir,0);
  538.             return(PFAILURE);
  539.         }
  540.         
  541.         break;
  542.         
  543.         more_comps:
  544.         /* Set the directory for the next component */
  545.  
  546.         /* At this point, clink contains the link for the next */
  547.         /* directory, and the directory itself is still filled */
  548.         /* in.  We should save away the directory information, */
  549.         /* then free what remains                              */
  550.         dir_version = clink->version;
  551.         dir_magic_no = clink->f_magic_no;
  552.  
  553.         strcpy(dir_type,clink->nametype);
  554.         strcpy(client_dir,clink->filename);
  555.         
  556.         if(strcmp(dir_type,"ASCII")) {
  557.             sendmf(req,"ERROR id-type %s not supported",dir_type,0);
  558.             plog(L_DIR_ERR,client_host,client_id,"Invalid id-type: %s",
  559.              command, 0);
  560.             /* Free the directory links */
  561.             vllfree(dir->links); dir->links = NULL;
  562.             vllfree(dir->ulinks); dir->ulinks = NULL;
  563.             aclfree(dir->dacl); dir->dacl = NULL;
  564.             return(PFAILURE);
  565.         }
  566.         
  567.         if(check_path(client_dir) == FALSE) {
  568.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  569.             plog(L_AUTH_ERR,client_host,client_id,
  570.              "Invalid directory name: %s",client_dir,0);
  571.             /* Free the directory links */
  572.             vllfree(dir->links); dir->links = NULL;
  573.             vllfree(dir->ulinks); dir->ulinks = NULL;
  574.             aclfree(dir->dacl); dir->dacl = NULL;
  575.             return(PFAILURE);
  576.         }
  577.  
  578.         components = remcomp;
  579.  
  580.         /* Free the directory links */
  581.         vllfree(dir->links); dir->links = NULL;
  582.         vllfree(dir->ulinks); dir->ulinks = NULL;
  583.         aclfree(dir->dacl); dir->dacl = NULL;
  584.         goto continue_list;
  585.  
  586.         case LIST: 
  587.         list_count++;
  588. #ifdef ARCHIE
  589.         if(max_list_commands-- <= 0) {
  590.             sendmf(req,"FAILURE NOT-AUTHORIZED Too many list commands in a single request",0);
  591.             plog(L_AUTH_ERR,client_host,client_id,
  592.              "Too many list commands",0);
  593.             return(PFAILURE);
  594.         }
  595. #endif /* ARCHIE */
  596.  
  597.         tmp = sscanf(command,"LIST %s COMPONENTS %[^\n]",
  598.                  t_options, t_name);
  599.  
  600.         if(tmp < 2) components = "*";
  601.         else components = t_name;
  602.  
  603.         /* If no options, parse again */
  604.         if(strcmp(t_options,"COMPONENTS")==0) {
  605.             tmp = sscanf(command,"LIST COMPONENTS %[^\n]", t_name);
  606.             if(tmp < 1) components = "*";
  607.             else components = t_name;
  608.         }
  609.  
  610.         if(sindex(t_options,"VERIFY")) verify_dir = 1;
  611.         else verify_dir = 0;
  612.  
  613. #ifndef DONTSUPPORTOLD
  614.         if(strcmp(components,"%#$PRobably_nOn_existaNT$#%")==0) {
  615.             components = "*";
  616.             verify_dir = 1;
  617.         }
  618. #endif
  619.  
  620.         /* If EXPAND specified, remeber that fact */
  621.         if(sindex(t_options,"EXPAND") || sindex(t_options,"LEXPAND")) 
  622.             localexp = 2;
  623.         else localexp = 0;
  624.  
  625.         if(sindex(t_options,"ATTRIBUTES")) attribfl = DSRD_ATTRIBUTES;
  626.         else attribfl = 0;
  627.  
  628.         plog(L_DIR_REQUEST, client_host, client_id, "L%s %s %s",
  629.              (verify_dir ? "V" : " "), client_dir, components, 0);
  630.         
  631.         /* Here's where we start to resolve additional components */
  632.         continue_list:
  633.         remcomp = index(components,'/');
  634.         if(remcomp) {
  635.             *(remcomp++) = '\0';
  636.             if(!*remcomp) remcomp = NULL;
  637.         }
  638.         uexp = NULL;
  639.  
  640.         /* If only expanding last component, clear the flag */
  641.         if(localexp == 1) localexp = 0;
  642.  
  643.         /* If remaining components, expand for this component only */
  644.         if(remcomp && !localexp) localexp = 1;
  645.  
  646. #ifdef NODOTDOT
  647.         if(strcmp(components,"..") == 0) {
  648.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  649.             plog(L_AUTH_ERR,client_host,client_id,
  650.              "Invalid component name: %s %s",client_dir,components,0);
  651.             return(PFAILURE);
  652.         }
  653. #endif NODOTDOT
  654.         
  655.         exp_ulink:
  656.  
  657.         *p_err_string = '\0';
  658.  
  659. #ifdef DATABASE_PREFIX
  660.         if(strncmp(client_dir,DATABASE_PREFIX,
  661.                strlen(DATABASE_PREFIX)) == 0) {
  662.             if(database_acl && !check_acl(database_acl,NULL,id,"r")) {
  663.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  664.             plog(L_AUTH_ERR,client_host,client_id,
  665.                  "Unauthorized database request: %s %s",client_dir,t_name,0); 
  666.             return(PFAILURE);
  667.             }
  668.             /* This could take a while, tell client not to retry */
  669.             transmit_wait(req,180); 
  670.             retval = dsdb(client_dir,&components,&remcomp,
  671.                   dir,verify_dir);
  672.         }
  673.         else
  674. #endif DATABASE_PREFIX
  675.         retval = dsrdir(client_dir,dir_magic_no,dir,uexp,attribfl);
  676.         if(retval == DSRFINFO_FORWARDED) goto dforwarded;
  677.         
  678.         /* If not a directory, say so */
  679.         if(retval == DSRDIR_NOT_A_DIRECTORY) {
  680.             sendmf(req,"NOT-A-DIRECTORY",0);
  681.             return(PFAILURE);
  682.         }
  683.  
  684.         /* If some other failure, say so */
  685.         if(retval == DIRSRV_NOT_AUTHORIZED) {
  686.             if(*p_err_string) 
  687.             sendmf(req,"FAILURE NOT-AUTHORIZED %s",p_err_string,0);
  688.             else sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  689.  
  690.             return(PFAILURE);
  691.         }
  692.  
  693.         /* If some other failure, say so */
  694.         if(retval) {
  695.             sendmf(req,"FAILURE SERVER-FAILED",0);
  696.             return(PFAILURE);
  697.         }
  698.  
  699.         /* Cache the default answers for ACL checks */
  700.         daclchkl = check_acl(dir->dacl,NULL,id,"l");
  701.         daclchkr = check_acl(dir->dacl,NULL,id,"r");
  702.  
  703.         /* Here we must send back the links, excluding those that do */
  704.         /* not match the component name. For each link, we must also */
  705.         /* send back any replicas or links with conflicting names    */
  706.         clink = dir->links;
  707.         while(clink) {
  708.           crep = clink;
  709.           while(crep) {
  710.             /* If ->expanded set means we already returned it */
  711.             if(crep->expanded) {
  712.             crep = crep->next;
  713.             continue;
  714.             }
  715.             /* Check individual ACL only if necessary */
  716.             laclchkl = daclchkl; laclchkr = daclchkr;
  717.             if(crep->acl) {
  718.             laclchkl = check_acl(dir->dacl,crep->acl,id,"l");
  719.             laclchkr = check_acl(dir->dacl,crep->acl,id,"r");
  720.             }
  721.             if(!verify_dir && wcmatch(crep->name,components) &&
  722.                (laclchkl || (laclchkr && 
  723.                      (strcmp(crep->name,components)==0)))) {
  724.             if(laclchkr) {
  725.                 if(remcomp && !strcmp(crep->host,hostwport) &&
  726.                    !(crep->filters) && !item_count) {
  727.                 /* If components remain on this host    */
  728.                 /* don't reply, but continue searching  */
  729.                 goto more_comps;
  730.                 }
  731.                 replyf(req,"LINK L %s %s %s %s %s %s %d %d",
  732.                    crep->type, quote(crep->name),
  733.                    crep->hosttype, crep->host,
  734.                    crep->nametype, crep->filename,
  735.                    crep->version,crep->f_magic_no,0);
  736.             }
  737.                 else {
  738.                 replyf(req,"LINK L NULL %s NULL NULL NULL NULL 0 0",
  739.                    quote(crep->name),0);
  740.             }
  741.             /* Using ->expanded to indicate returned */
  742.             crep->expanded = TRUE;
  743.             item_count++;
  744.             /* If link attributes are to be returned, do so */
  745.             /* For now, only link attributes returned       */
  746.             ca = crep->lattrib;
  747.             while(ca && attribfl) {
  748.              /* For now return all attributes. To be done: */
  749.              /* return only those requested                */
  750.              if(1) {
  751.                replyf(req,"LINK-INFO %s %s %s %s",
  752.                 ((ca->precedence==ATR_PREC_LINK) ? "LINK":
  753.                 ((ca->precedence==ATR_PREC_REPLACE)? "REPLACEMENT":
  754.                 ((ca->precedence==ATR_PREC_ADD) ? "ADDITIONAL":
  755.                 "CACHED"))),
  756.                 ca->aname,ca->avtype,ca->value.ascii,0);
  757.                  }
  758.              ca = ca->next;
  759.                 }
  760.  
  761.             /* If there are any filters, send them back too */ 
  762.             cfil = crep->filters;
  763.             while(cfil && laclchkr) {
  764.                 if(cfil->args) replyf(req,"FILTER %c %s %s %s %s %d %d ARGS '%s'",
  765.                           cfil->linktype, 
  766.                           cfil->hosttype, cfil->host,
  767.                           cfil->nametype, cfil->filename,
  768.                           cfil->version,cfil->f_magic_no,
  769.                           /* Handle qwuoting properly*/
  770.                           /*quote(*/cfil->args/*)*/,0);
  771.                 else replyf(req,"FILTER %c %s %s %s %s %d %d",
  772.                     cfil->linktype, 
  773.                     cfil->hosttype, cfil->host,
  774.                     cfil->nametype, cfil->filename,
  775.                     cfil->version,cfil->f_magic_no,0);
  776.                 cfil = cfil->next;
  777.             }
  778.             }
  779.             /* Replicas are linked through next, not replicas */
  780.             /* But the primary link is linked to the replica  */
  781.             /* list through replicas                          */
  782.             if(crep == clink) crep = crep->replicas;
  783.             else crep = crep->next;
  784.           }
  785.           clink = clink->next;
  786.         }
  787.         /* here we must send back the unexpanded union links */
  788.         clink = dir->ulinks;
  789.         while(clink && !verify_dir) {
  790.             if(!clink->expanded &&
  791.                check_acl(dir->dacl,clink->acl,id,"r")) {
  792.             if(localexp && !(clink->filters) &&
  793.                !strcmp(clink->host,hostwport)) {
  794.                 /* Set the directory for the next component   */
  795.                 /* At this point, clink contains the link     */
  796.                 /* for the next directory                     */
  797.                 dir_version = clink->version;
  798.                 dir_magic_no = clink->f_magic_no;
  799.  
  800.                 strcpy(dir_type,clink->nametype);
  801.                 strcpy(client_dir,clink->filename);
  802.         
  803.                 if(strcmp(dir_type,"ASCII")) {
  804.                 sendmf(req,"ERROR id-type %s not supported",
  805.                        dir_type,0);
  806.                 plog(L_DIR_ERR,client_host,client_id,
  807.                      "Invalid id-type: %s", command, 0);
  808.                 /* Free the directory links */
  809.                 vllfree(dir->links); dir->links = NULL;
  810.                 vllfree(dir->ulinks); dir->ulinks = NULL;
  811.                 aclfree(dir->dacl); dir->dacl = NULL;
  812.                 return(PFAILURE);
  813.                 }
  814.         
  815.                 if(check_path(client_dir) == FALSE) {
  816.                 sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  817.                 plog(L_AUTH_ERR,client_host,client_id,
  818.                      "Invalid directory name: %s",client_dir,0);
  819.                 /* Free the directory links */
  820.                 vllfree(dir->links); dir->links = NULL;
  821.                 vllfree(dir->ulinks); dir->ulinks = NULL;
  822.                 aclfree(dir->dacl); dir->dacl = NULL;
  823.                 return(PFAILURE);
  824.                 }
  825.                 clink->expanded = TRUE;
  826.                 uexp = clink;
  827.                 goto exp_ulink;
  828.             }
  829.             /* Don't do any more expanding */
  830.             localexp = 0;
  831.             replyf(req,"LINK %c %s %s %s %s %s %s %d %d",
  832.                    clink->linktype,
  833.                    clink->type, quote(clink->name),
  834.                    clink->hosttype, clink->host,
  835.                    clink->nametype,clink->filename,
  836.                    clink->version,clink->f_magic_no,0);
  837.             item_count++;
  838.             /* if there are any filters */
  839.             cfil = clink->filters;
  840.             while(cfil) {
  841.                 if(cfil->args) replyf(req,"FILTER %c %s %s %s %s %d %d ARGS '%s'",
  842.                           cfil->linktype, 
  843.                           cfil->hosttype, cfil->host,
  844.                           cfil->nametype, cfil->filename,
  845.                           cfil->version,cfil->f_magic_no,
  846.                           /* Handle quoting properly*/
  847.                           /*quote(*/cfil->args/*)*/,0);
  848.                 else replyf(req,"FILTER %c %s %s %s %s %d %d",
  849.                     cfil->linktype, 
  850.                     cfil->hosttype, cfil->host,
  851.                     cfil->nametype, cfil->filename,
  852.                     cfil->version,cfil->f_magic_no,0);
  853.                 cfil = cfil->next;
  854.             }
  855.             }
  856.             clink = clink->next;
  857.         }
  858.         
  859.         /* If none, match, say so */
  860.         if(!item_count)
  861.             replyf(req,"NONE-FOUND",0);
  862.         /* Otherwise, if components remain say so */
  863.         else if(remcomp && *remcomp) 
  864.             replyf(req,"UNRESOLVED %s",remcomp,0);
  865.  
  866.         /* Free the directory links */
  867.         vllfree(dir->links); dir->links = NULL;
  868.         vllfree(dir->ulinks); dir->ulinks = NULL;
  869.         aclfree(dir->dacl); dir->dacl = NULL;
  870.         break;
  871.         
  872.         case LIST_ACL: 
  873.         lacl_count++;
  874.         
  875.         *t_name = '\0';
  876.  
  877.         /* First arg is options.  All others are optional. */
  878.         /* If a second argument is specified, it is the    */
  879.         /* link for which the ACL is to be returned        */
  880.         /* if the OBJECT option is specified, then args    */
  881.         /* 2-5 identify the object instead of the link     */
  882.         tmp = sscanf(command,"LIST-ACL %s %s %*s %*d %*d",
  883.                  t_options, t_name);
  884.         
  885.         /* Log and return a better message */
  886.         if((tmp < 1) || 
  887.            ((tmp < 2) && (strcmp(t_options,"DIRECTORY") != 0)))  {
  888.             sendmf(req,"ERROR too few arguments",0);
  889.             plog(L_DIR_PERR,client_host,client_id,"Too few arguments: %s",
  890.              command, 0);
  891.             return(PFAILURE);
  892.         }
  893.         
  894.         /* Do we need a better log message */
  895.         plog(L_DIR_REQUEST,client_host,client_id,"LA %s %s",
  896.              client_dir,t_name,0);
  897.  
  898.         retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
  899.         if(retval == DSRFINFO_FORWARDED) goto dforwarded;
  900.         
  901.         /* If not a directory, say so */
  902.         if(retval == DSRDIR_NOT_A_DIRECTORY) {
  903.             sendmf(req,"NOT-A-DIRECTORY",0);
  904.             plog(L_DIR_ERR, client_host, client_id, 
  905.              "Invalid directory name: %s", client_dir,0);
  906.             return(PFAILURE);
  907.         }
  908.         
  909.         wacl = NULL;
  910.  
  911.         /* Only LINK and DIRECTORY are presently implemented */
  912.         if(sindex(t_options,"LINK")) {
  913.             /* Need to find the link so we can check its ACL */
  914.             clink = dir->links;
  915.             while(clink) {
  916.             if(strcmp(clink->name,t_name) == 0)
  917.                 break;
  918.             clink = clink->next;
  919.             }
  920.             if(!clink) {
  921.             clink = dir->ulinks;
  922.             while(clink) {
  923.                 if(strcmp(clink->name,t_name) == 0)
  924.                 break;
  925.                 clink = clink->next;
  926.             }         
  927.             }
  928.             if(!clink) {
  929.             sendmf(req,"FAILURE NOT-FOUND LINK %s",t_name,0);
  930.             plog(L_DIR_ERR,client_host,client_id,"Link not found: %s %s",
  931.                  client_dir, t_name,0);
  932.             vllfree(dir->links); dir->links = NULL;
  933.             vllfree(dir->ulinks); dir->ulinks = NULL;
  934.             aclfree(dir->dacl); dir->dacl = NULL;
  935.             return(PFAILURE);
  936.             }
  937.             wacl = clink->acl;
  938.             aclchk = check_acl(dir->dacl,clink->acl,id,"v");
  939.         }
  940.         else if(sindex(t_options,"DIRECTORY")) {
  941.             wacl = dir->dacl;
  942.             aclchk = check_acl(dir->dacl,NULL,id,"V");
  943.         }
  944.         else {
  945.             sendmf(req,"ERROR invalid option",0);
  946.             plog(L_DIR_PERR,client_host,client_id,"Invalid option: %s",
  947.              command, 0);
  948.             /* Free the directory links */
  949.             vllfree(dir->links); dir->links = NULL;
  950.             vllfree(dir->ulinks); dir->ulinks = NULL;
  951.             aclfree(dir->dacl); dir->dacl = NULL;
  952.             return(PFAILURE);
  953.         }
  954.  
  955.         /* If not authorized, say so */
  956.         if(!aclchk) {
  957.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  958.             plog(L_AUTH_ERR,client_host,client_id,
  959.              "Unauthorized LIST-ACL: %s %s",client_dir,t_name,0); 
  960.             /* Free the directory links */
  961.             vllfree(dir->links); dir->links = NULL;
  962.             vllfree(dir->ulinks); dir->ulinks = NULL;
  963.             aclfree(dir->dacl); dir->dacl = NULL;
  964.             return(PFAILURE);
  965.         }
  966.  
  967.         if(wacl == NULL) {
  968.             if(sindex(t_options,"LINK")) /* Link default is diracl */
  969.             replyf(req,"ACL DIRECTORY '' '' ''",0);
  970.             else {
  971.             replyf(req,"ACL DEFAULT '' '' ''",0);
  972.             replyf(req,"ACL SYSTEM '' '' ''",0);
  973.             }
  974.         }
  975.         else while (wacl) {
  976.             strcpy(qatype,quote(wacl->atype));
  977.             strcpy(qrights,quote(wacl->rights));
  978.             replyf(req,"ACL %s %s %s %s",
  979.                acltypes[wacl->acetype],qatype,
  980.                qrights,quote(wacl->principals),0);
  981.             wacl = wacl->next;
  982.         }
  983.         
  984.         vllfree(dir->links); dir->links = NULL;
  985.         vllfree(dir->ulinks); dir->ulinks = NULL;
  986. #ifdef DATABASE_PREFIX
  987.         if(strcmp(client_dir,DATABASE_PREFIX) == 0) {
  988.             aclfree(database_acl);
  989.             database_acl = dir->dacl;
  990.         } else
  991. #endif            
  992.             aclfree(dir->dacl); 
  993.         dir->dacl = NULL;
  994.         break;
  995.  
  996. #ifndef PSRV_READ_ONLY
  997.         case UPDATE: 
  998.         upddir_count++;
  999.         components = sindex(command,"COMPONENTS");
  1000.         
  1001.         if(!components || (strlen(components) < 12)) components = "*";
  1002.         else components += 11;
  1003.         
  1004.         plog(L_DIR_UPDATE, client_host, client_id, "U %s %s",
  1005.              client_dir, components,0);
  1006.         
  1007.         retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
  1008.         if(retval == DSRFINFO_FORWARDED) goto dforwarded;
  1009.         
  1010.         /* If not a directory, say so */
  1011.         if(retval == DSRDIR_NOT_A_DIRECTORY) {
  1012.             sendmf(req,"NOT-A-DIRECTORY",0);
  1013.             plog(L_DIR_ERR, client_host, client_id, 
  1014.              "Invalid directory name: %s", client_dir,0);
  1015.             return(PFAILURE);
  1016.         }
  1017.         
  1018.         /* Here we must check for forwarding of each link and */
  1019.         /* update it to reflect the new target                */
  1020.         clink = dir->links;
  1021.         while(clink) {
  1022.             if(wcmatch(clink->name,components)) {
  1023.             /* Check for forwarding */
  1024.             if(retrieve_fp(clink) == PSUCCESS) item_count++;
  1025.             
  1026.             /* If filters, check them too */
  1027.             cfil = clink->filters;
  1028.             while(cfil) {
  1029.                 if(retrieve_fp(cfil) == PSUCCESS) item_count++;
  1030.                 cfil = cfil->next;
  1031.             }
  1032.             }
  1033.             clink = clink->next;
  1034.         }
  1035.         
  1036.         /* here we must process the union, */
  1037.         /* replica and propagate links     */
  1038.         clink = dir->ulinks;
  1039.         while(clink) {
  1040.             if(wcmatch(clink->name,components)) {
  1041.             /* Check for forwarding */
  1042.             if(retrieve_fp(clink) == PSUCCESS) item_count++;
  1043.             
  1044.             /* If filters, check them too ***/
  1045.             cfil = clink->filters;
  1046.             while(cfil) {
  1047.                 if(retrieve_fp(cfil) == PSUCCESS) item_count++;
  1048.                 cfil = cfil->next;
  1049.             }
  1050.             }
  1051.             clink = clink->next;
  1052.         }
  1053.         
  1054.         retval = 0;
  1055.         if(item_count) retval = dswdir(client_dir,dir);
  1056.         
  1057.         /* Indicate how many updated */
  1058.         if(retval) replyf(req,"FAILED to UPDATE %d links",item_count,0);
  1059.         else replyf(req,"UPDATED %d links",item_count,0);
  1060.         
  1061.         /* Free the directory links */
  1062.         vllfree(dir->links); dir->links = NULL;
  1063.         vllfree(dir->ulinks); dir->ulinks = NULL;
  1064.         aclfree(dir->dacl); dir->dacl = NULL;
  1065.         break;
  1066.         
  1067.         case CREATE_LINK: 
  1068.         crlnk_count++;
  1069.         clink = vlalloc();
  1070.         
  1071.         tmp = sscanf(command,"CREATE-LINK %c %s %s %s %s %s %s %d %d",
  1072.                  &t_ltype,t_name,t_type,t_htype,t_host,
  1073.                  t_ntype,t_fname,
  1074.                  &(clink->version),&(clink->f_magic_no));
  1075.         
  1076.         /* Log and return a better message */
  1077.         if(tmp < 7) {
  1078.             sendmf(req,"ERROR too few arguments",0);
  1079.             plog(L_DIR_PERR, client_host, client_id, 
  1080.              "Too few arguments: %s", command, 0);
  1081.             return(PFAILURE);
  1082.         }
  1083.         
  1084.         if (t_ltype == 'U') clink->linktype = 'U';
  1085.         
  1086.         clink->name = stcopyr(unquote(t_name),clink->name);
  1087.         clink->type = stcopyr(t_type,clink->type);
  1088.         clink->hosttype = stcopyr(t_htype,clink->hosttype);
  1089.         clink->host = stcopyr(t_host,clink->host);
  1090.         clink->nametype = stcopyr(t_ntype,clink->nametype);
  1091.         clink->filename = stcopyr(t_fname,clink->filename);
  1092.         
  1093.         /* Do we need a better log message */
  1094.         plog(L_DIR_UPDATE, client_host, client_id, 
  1095.              "CL %s %c %s %s %s %s %s %s", client_dir,
  1096.              clink->linktype, clink->name, clink->type, clink->hosttype,
  1097.              clink->host, clink->nametype,clink->filename,0);
  1098.         
  1099.         retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
  1100.         if(retval == DSRFINFO_FORWARDED) goto dforwarded;
  1101.         
  1102.         /* If not a directory, say so */
  1103.         if(retval == DSRDIR_NOT_A_DIRECTORY) {
  1104.             sendmf(req,"NOT-A-DIRECTORY",0);
  1105.             plog(L_DIR_ERR, client_host, client_id, 
  1106.              "Invalid directory name: %s", client_dir,0);
  1107.             return(PFAILURE);
  1108.         }
  1109.         
  1110.         /* If not authorized, say so */
  1111.         if(!check_acl(dir->dacl,NULL,id,"I")) {
  1112.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  1113.             plog(L_AUTH_ERR,client_host,client_id,
  1114.              "Unauthorized CREATE-LINK: %s %s",client_dir,
  1115.              components,0); 
  1116.             /* Free the directory links */
  1117.             vllfree(dir->links); dir->links = NULL;
  1118.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1119.             aclfree(dir->dacl); dir->dacl = NULL;
  1120.             return(PFAILURE);
  1121.         }
  1122.             
  1123.         /* Make sure creator has all rights to link */
  1124.         if(!check_acl(dir->dacl,NULL,id,"alrmd")) {
  1125.             /* If not, grant full access */
  1126.             nacl = acalloc();
  1127.             nacl->acetype = ACL_ASRTHOST;
  1128.             nacl->rights = stcopyr("alrmd",nacl->rights);
  1129.             nacl->principals = stcopyr(id->userid,nacl->principals);
  1130.             change_acl(&(clink->acl),nacl,id,MACL_ADD|MACL_LINK,dir->dacl);
  1131.         }
  1132.  
  1133.         retval = vl_insert(clink,dir,VLI_NOCONFLICT);
  1134.         if((retval == VL_INSERT_ALREADY_THERE) ||
  1135.            (retval == UL_INSERT_ALREADY_THERE))    {
  1136.             sendmf(req,"FAILURE ALREADY-EXISTS %s",clink->name,0);
  1137.             /* Free the directory links */
  1138.             vllfree(dir->links); dir->links = NULL;
  1139.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1140.             aclfree(dir->dacl); dir->dacl = NULL;
  1141.             return(PFAILURE);
  1142.         }
  1143.         else if(retval == VL_INSERT_CONFLICT) {
  1144.             sendmf(req,"FAILURE NAME-CONFLICT %s",clink->name,0);
  1145.             plog(L_DIR_ERR, client_host, client_id,
  1146.              "Conflicting link already exists: %s %s", client_dir, clink->name,0);
  1147.             /* Free the directory links */
  1148.             vllfree(dir->links); dir->links = NULL;
  1149.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1150.             aclfree(dir->dacl); dir->dacl = NULL;
  1151.             return(PFAILURE);
  1152.         }
  1153.         
  1154.         if(!retval) retval = dswdir(client_dir,dir);
  1155.         
  1156.         /* if successfull say so (need to clean this up) */
  1157.         if(!retval)
  1158.             replyf(req,"SUCCESS",0);
  1159.         else replyf(req,"FAILURE",0);
  1160.         
  1161.         /* Free the directory links */
  1162.         vllfree(dir->links); dir->links = NULL;
  1163.         vllfree(dir->ulinks); dir->ulinks = NULL;
  1164.         aclfree(dir->dacl); dir->dacl = NULL;
  1165.         break;
  1166.  
  1167.         case MODIFY_ACL: 
  1168.         macl_count++;
  1169.         
  1170.         *t_name = '\0';
  1171.  
  1172.         tmp = sscanf(command,"MODIFY-ACL %s %s %s %s %s %[^\n]",
  1173.                  t_options, t_name, t_acetype, t_atype,
  1174.                  t_rights, t_principals);
  1175.         
  1176.         /* Log and return a better message */
  1177.         if(tmp < 6) {
  1178.             sendmf(req,"ERROR too few arguments",0);
  1179.             plog(L_DIR_PERR,client_host,client_id,"Too few arguments: %s",
  1180.              command, 0);
  1181.             return(PFAILURE);
  1182.         }
  1183.         
  1184.         /* Do we need a better log message */
  1185.         plog(L_DIR_UPDATE,client_host,client_id,"MA %s %s %s %s %s %s %s",
  1186.              client_dir,t_name,t_options,t_acetype,t_atype,t_rights,
  1187.              t_principals,0);
  1188.  
  1189.         strcpy(t_name,unquote(t_name));
  1190.  
  1191.         nacl = acalloc();
  1192.  
  1193.         for(nacl->acetype = 0;acltypes[nacl->acetype];(nacl->acetype)++) {
  1194.             if(strcmp(acltypes[nacl->acetype],t_acetype)==0)
  1195.             break;
  1196.         }
  1197.         if(acltypes[nacl->acetype] == NULL) nacl->acetype = 0;
  1198.  
  1199.         nacl->atype = stcopyr(unquoten(t_atype),nacl->atype);
  1200.         nacl->rights = stcopyr(unquoten(t_rights),nacl->rights);
  1201.         nacl->principals = stcopyr(unquoten(t_principals),nacl->principals);
  1202.         retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
  1203.         if(retval == DSRFINFO_FORWARDED) goto dforwarded;
  1204.  
  1205.         /* If not a directory, say so */
  1206.         if(retval == DSRDIR_NOT_A_DIRECTORY) {
  1207.             sendmf(req,"NOT-A-DIRECTORY",0);
  1208.             plog(L_DIR_ERR, client_host, client_id, 
  1209.              "Invalid directory name: %s", client_dir,0);
  1210.             return(PFAILURE);
  1211.         }
  1212.         
  1213.         
  1214.         n_options = 0;
  1215.  
  1216.         /* Parse the options */
  1217.         if(sindex(t_options,"NOSYSTEM")!=NULL) n_options|=MACL_NOSYSTEM;
  1218.         if(sindex(t_options,"NOSELF")!=NULL) n_options|=MACL_NOSELF;
  1219.         if(sindex(t_options,"DEFAULT")!=NULL) n_options|=MACL_DEFAULT;
  1220.         if(sindex(t_options,"SET") != NULL) n_options |= MACL_SET;
  1221.         if(sindex(t_options,"INSERT")!=NULL) n_options|=MACL_INSERT;
  1222.         if(sindex(t_options,"DELETE")!=NULL) n_options|=MACL_DELETE;
  1223.         if(sindex(t_options,"ADD")!=NULL) n_options|=MACL_ADD;
  1224.         if(sindex(t_options,"SUBTRACT")!=NULL) n_options|=MACL_SUBTRACT;
  1225.         if(sindex(t_options,"LINK")!=NULL) n_options|=MACL_LINK;
  1226.         if(sindex(t_options,"DIRECTORY")!=NULL) n_options|=MACL_DIRECTORY;
  1227.         if(sindex(t_options,"OBJECT")!=NULL) n_options|=MACL_OBJECT;
  1228.         if(sindex(t_options,"INCLUDE")!=NULL) n_options|=MACL_INCLUDE;
  1229.  
  1230.         wacl = dir->dacl;
  1231.         if(!((n_options&MACL_OTYPE)^MACL_LINK)) {
  1232.             /* Need to find the link so we can change its ACL */
  1233.             clink = dir->links;
  1234.             while(clink) {
  1235.             if(strcmp(clink->name,t_name) == 0)
  1236.                 break;
  1237.             clink = clink->next;
  1238.             }
  1239.             if(!clink) {
  1240.             clink = dir->ulinks;
  1241.             while(clink) {
  1242.                 if(strcmp(clink->name,t_name) == 0)
  1243.                 break;
  1244.                 clink = clink->next;
  1245.             }         
  1246.             }
  1247.             if(!clink) {
  1248.             sendmf(req,"FAILURE NOT-FOUND LINK %s",t_name,0);
  1249.             plog(L_DIR_ERR,client_host,client_id,"Link not found: %s %s",
  1250.                  client_dir, t_name,0);
  1251.             /* Free the directory links */
  1252.             vllfree(dir->links); dir->links = NULL;
  1253.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1254.             aclfree(dir->dacl); dir->dacl = NULL;
  1255.             return(PFAILURE);
  1256.             }
  1257.             if(clink->acl) wacl = clink->acl;
  1258.             /* Check and update link ACL */
  1259.             aclchk = check_acl(dir->dacl,clink->acl,id,"a");
  1260.             if(!aclchk && nacl->rights && *(nacl->rights) &&
  1261.                (!((n_options&MACL_OP)^MACL_ADD) ||
  1262.             !((n_options&MACL_OP)^MACL_INSERT) ||
  1263.             !((n_options&MACL_OP)^MACL_SUBTRACT) ||
  1264.             !((n_options&MACL_OP)^MACL_DELETE))) {
  1265.             if(!((n_options&MACL_OP)^MACL_ADD) ||
  1266.                !((n_options&MACL_OP)^MACL_INSERT))
  1267.                 *insrights = ']';
  1268.             else *insrights = '[';
  1269.             strcpy(insrights+1,nacl->rights);
  1270.             aclchk = check_acl(dir->dacl,clink->acl,id,insrights);
  1271.             /* Don't use this to upgrade [ to a */
  1272.             if(aclchk) n_options |= MACL_NOSELF;
  1273.             }
  1274.             /* If not authorized, say so */
  1275.             if(!aclchk) {
  1276.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  1277.             plog(L_AUTH_ERR,client_host,client_id,
  1278.                  "Unauthorized LIST-ACL: %s %s",client_dir,t_name,0); 
  1279.             /* Free the directory links */
  1280.             vllfree(dir->links); dir->links = NULL;
  1281.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1282.             aclfree(dir->dacl); dir->dacl = NULL;
  1283.             return(PFAILURE);
  1284.             }
  1285.              retval = change_acl(&(clink->acl),nacl,id,n_options,dir->dacl);
  1286.         }
  1287.         else if(!((n_options&MACL_OTYPE)^MACL_DIRECTORY)) {
  1288.             /* Check and update directory ACL */
  1289.             aclchk = check_acl(dir->dacl,NULL,id,"A");
  1290.             if(!aclchk && nacl->rights && *(nacl->rights) &&
  1291.                (!((n_options&MACL_OP)^MACL_ADD) ||
  1292.             !((n_options&MACL_OP)^MACL_INSERT) ||
  1293.             !((n_options&MACL_OP)^MACL_SUBTRACT) ||
  1294.             !((n_options&MACL_OP)^MACL_DELETE))) {
  1295.             if(!((n_options&MACL_OP)^MACL_ADD) ||
  1296.                !((n_options&MACL_OP)^MACL_INSERT))
  1297.                 *insrights = '>';
  1298.             else *insrights = '<';
  1299.             strcpy(insrights+1,nacl->rights);
  1300.             aclchk = check_acl(dir->dacl,NULL,id,insrights);
  1301.             /* Don't use this to upgrade < to a */
  1302.             if(aclchk) n_options |= MACL_NOSELF;
  1303.             }
  1304.             /* If not authorized, say so */
  1305.             if(!aclchk) {
  1306.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  1307.             plog(L_AUTH_ERR,client_host,client_id,
  1308.                  "Unauthorized LIST-ACL: %s %s",client_dir,t_name,0); 
  1309.             /* Free the directory links */
  1310.             vllfree(dir->links); dir->links = NULL;
  1311.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1312.             aclfree(dir->dacl); dir->dacl = NULL;
  1313.             return(PFAILURE);
  1314.             }
  1315.             retval = change_acl(&(dir->dacl),nacl,id,n_options,dir->dacl);
  1316.         }
  1317.         else {
  1318.             sendmf(req,"ERROR invalid option",0);
  1319.             plog(L_DIR_PERR,client_host,client_id,"Invalid option: %s",
  1320.              command, 0);
  1321.             /* Free the directory links */
  1322.             vllfree(dir->links); dir->links = NULL;
  1323.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1324.             aclfree(dir->dacl); dir->dacl = NULL;
  1325.             return(PFAILURE);
  1326.         }
  1327.  
  1328.         /* if unsuccessfull say so (need to clean this up) */
  1329.         if(retval) replyf(req,"FAILURE NOT-FOUND ACL",0);
  1330.         else { /* Otherwise write the directory and indicate success */
  1331.             retval = dswdir(client_dir,dir);
  1332.             if(retval) replyf(req,"FAILURE",0);
  1333.             else replyf(req,"SUCCESS",0);
  1334.         }
  1335.  
  1336.         vllfree(dir->links); dir->links = NULL;
  1337.         vllfree(dir->ulinks); dir->ulinks = NULL;
  1338.         aclfree(dir->dacl); dir->dacl = NULL;
  1339.         break;
  1340.  
  1341.         case MODIFY_LINK: 
  1342.         modl_count++;
  1343.         cfil = vlalloc();
  1344.         
  1345.         tmp = sscanf(command,"MODIFY-LINK %s FILTER ADD %c %s %s %s %s %d %d ARGS '%[^']",
  1346.                  t_name,&t_ltype,t_htype,t_host,t_ntype,t_fname,
  1347.                  &(cfil->version),&(cfil->f_magic_no),t_args);
  1348.         
  1349.         /* Log and return a better message */
  1350.         if(tmp < 6) {
  1351.             sendmf(req,"ERROR too few arguments",0);
  1352.             plog(L_DIR_PERR, client_host, client_id,
  1353.              "Too few arguments: %s", command, 0);
  1354.             return(PFAILURE);
  1355.         }
  1356.         
  1357.         cfil->linktype = t_ltype;
  1358.         cfil->hosttype = stcopyr(t_htype,cfil->hosttype);
  1359.         cfil->host = stcopyr(t_host,cfil->host);
  1360.         cfil->nametype = stcopyr(t_ntype,cfil->nametype);
  1361.         cfil->filename = stcopyr(t_fname,cfil->filename);
  1362.         
  1363.         if(tmp == 9) cfil->args = stcopyr(t_args,cfil->args);
  1364.         
  1365.         /* Do we need a better log message */
  1366.         plog(L_DIR_UPDATE, client_host, client_id,
  1367.              "ML %s %s FA %c %s %s %s %s ARGS '%s'", client_dir,
  1368.              t_name, cfil->linktype, cfil->hosttype, cfil->host,
  1369.              cfil->nametype,cfil->filename, cfil->args,0);
  1370.         
  1371.         retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
  1372.         if(retval == DSRFINFO_FORWARDED) goto dforwarded;
  1373.         
  1374.         /* If not a directory, say so */
  1375.         if(retval == DSRDIR_NOT_A_DIRECTORY) {
  1376.             sendmf(req,"NOT-A-DIRECTORY",0);
  1377.             plog(L_DIR_ERR, client_host, client_id,
  1378.              "Invalid directory name: %s", client_dir,0);
  1379.             return(PFAILURE);
  1380.         }
  1381.         
  1382.         clink = dir->links;
  1383.         while(clink) {
  1384.             if(strcmp(clink->name,t_name) == 0)
  1385.             break;
  1386.             clink = clink->next;
  1387.         }
  1388.         if(!clink) {
  1389.             clink = dir->ulinks;
  1390.             while(clink) {
  1391.             if(strcmp(clink->name,t_name) == 0)
  1392.                 break;
  1393.             clink = clink->next;
  1394.             }         
  1395.         }
  1396.         if(!clink) {
  1397.             sendmf(req,"FAILURE NOT-FOUND LINK %s",t_name,0);
  1398.             plog(L_DIR_ERR,client_host,client_id,"Link not found: %s %s",
  1399.              client_dir, t_name,0);
  1400.             /* Free the directory links */
  1401.             vllfree(dir->links); dir->links = NULL;
  1402.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1403.             aclfree(dir->dacl); dir->dacl = NULL;
  1404.             return(PFAILURE);
  1405.         }
  1406.         
  1407.         /* If not authorized, say so */
  1408.         if(!check_acl(dir->dacl,clink->acl,id,"m")) {
  1409.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  1410.             plog(L_AUTH_ERR,client_host,client_id,
  1411.              "Unauthorized MODIFY-LINK: %s %s",client_dir,
  1412.              clink->name,0); 
  1413.             /* Free the directory links */
  1414.             vllfree(dir->links); dir->links = NULL;
  1415.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1416.             aclfree(dir->dacl); dir->dacl = NULL;
  1417.             return(PFAILURE);
  1418.         }
  1419.  
  1420.         fl_insert(cfil,clink);
  1421.         
  1422.         if(!retval) retval = dswdir(client_dir,dir);
  1423.         
  1424.         /* if successfull say so (need to clean this up) */
  1425.         if(!retval)
  1426.             replyf(req,"SUCCESS",0);
  1427.         else replyf(req,"FAILURE",0);
  1428.         
  1429.         /* Free the directory links */
  1430.         vllfree(dir->links); dir->links = NULL;
  1431.         vllfree(dir->ulinks); dir->ulinks = NULL;
  1432.         aclfree(dir->dacl); dir->dacl = NULL;
  1433.         break;
  1434.  
  1435.         case CREATE_DIRECTORY: 
  1436.         crdir_count++;
  1437.         clink = vlalloc();
  1438.         
  1439.         /* still have to read the remainder of the attributes */
  1440.         tmp = sscanf(command,"CREATE-DIRECTORY %s %s",
  1441.                  t_options,t_name);
  1442.         
  1443.         /* Log and return a better message */
  1444.         if(tmp < 2) {
  1445.             sendmf(req,"ERROR too few arguments",0);
  1446.             plog(L_DIR_PERR,client_host,client_id,"Too few arguments: %s",
  1447.              command, 0);
  1448.             return(PFAILURE);
  1449.         }
  1450.  
  1451.         /* For now, VIRTRUAL option must be specified */
  1452.         if(sindex(t_options,"VIRTUAL") == NULL) {
  1453.             sendmf(req,"ERROR only VIRTUAL directories implemented",0);
  1454.             plog(L_DIR_PERR,client_host,client_id,"Tried to create non-VIRTUAL directory: %s",
  1455.              command, 0);
  1456.             return(PFAILURE);
  1457.         }
  1458.         
  1459.         if(sindex(t_options,"LPRIV")) lpriv = 1;
  1460.         else lpriv = 0;
  1461.  
  1462.         clink->name = stcopyr(t_name,clink->name);
  1463.         clink->type = stcopyr("DIRECTORY",clink->type);
  1464.         clink->host = stcopyr(hostwport,clink->host);
  1465.         
  1466.         strcpy(t_fname,client_dir);
  1467.         strcat(t_fname,"/");
  1468.         strcat(t_fname,t_name);
  1469.         
  1470.         clink->filename = stcopyr(t_fname,clink->filename);
  1471.         
  1472.         /* Do we need a better log message */
  1473.         plog(L_DIR_UPDATE,client_host,client_id,"MKD %s %s",
  1474.              client_dir, clink->name,0);
  1475.         
  1476.         retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
  1477.         if(retval == DSRFINFO_FORWARDED) goto dforwarded;
  1478.         
  1479.         /* If not a directory, say so */
  1480.         if(retval == DSRDIR_NOT_A_DIRECTORY) {
  1481.             sendmf(req,"NOT-A-DIRECTORY",0);
  1482.             plog(L_DIR_ERR, client_host, client_id, 
  1483.              "Invalid directory name: %s", client_dir,0);
  1484.             return(PFAILURE);
  1485.         }
  1486.         
  1487.         /* If not authorized, say so */
  1488.         if(!check_acl(dir->dacl,NULL,id,"I")) {
  1489.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  1490.             plog(L_AUTH_ERR,client_host,client_id,
  1491.              "Unauthorized CREATE-DIRECTORY: %s %s",client_dir,
  1492.              components,0); 
  1493.             /* Free the directory links */
  1494.             vllfree(dir->links); dir->links = NULL;
  1495.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1496.             aclfree(dir->dacl); dir->dacl = NULL;
  1497.             return(PFAILURE);
  1498.         }
  1499.  
  1500.         retval = vl_insert(clink,dir,VLI_NOCONFLICT);
  1501.         if(retval == VL_INSERT_ALREADY_THERE) {
  1502.             sendmf(req,"FAILURE ALREADY-EXISTS %s",clink->name,0);
  1503.             /* Free the directory links */
  1504.             vllfree(dir->links); dir->links = NULL;
  1505.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1506.             aclfree(dir->dacl); dir->dacl = NULL;
  1507.             return(PFAILURE);
  1508.         }
  1509.         else if(retval == VL_INSERT_CONFLICT) {
  1510.             sendmf(req,"FAILURE NAME-CONFLICT %s",clink->name,0);
  1511.             plog(L_DIR_ERR,client_host,client_id,
  1512.              "Conflicting link already exists: %s %s",client_dir,clink->name,0);
  1513.             /* Free the directory links */
  1514.             vllfree(dir->links); dir->links = NULL;
  1515.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1516.             aclfree(dir->dacl); dir->dacl = NULL;
  1517.             return(PFAILURE);
  1518.         }
  1519.  
  1520.         if(!retval) retval = dswdir(client_dir,dir);
  1521.  
  1522.         /* We should check if the new directory already */
  1523.         /* exists and if so pick a new name for the     */
  1524.         /* physical instantiation ****                  */
  1525.  
  1526.         /* Free the directory links, but leave ACL */
  1527.         vllfree(dir->links); dir->links = NULL;
  1528.         vllfree(dir->ulinks); dir->ulinks = NULL;
  1529.         dir->inc_native = FALSE;
  1530.         
  1531.         /* Add creator to the ACL */
  1532.         if(!lpriv || (!check_acl(dir->dacl,NULL,id,"AIlr"))) {
  1533.             nacl = acalloc();
  1534.             nacl->acetype = ACL_ASRTHOST;
  1535.             if(lpriv) nacl->rights = stcopyr("AIlr",nacl->rights);
  1536.             else nacl->rights = stcopyr("ALRMDI",nacl->rights);
  1537.             nacl->principals = stcopyr(id->userid,nacl->principals);
  1538.             change_acl(&(dir->dacl),nacl,id,MACL_ADD|MACL_DIRECTORY,dir->dacl);
  1539.         }
  1540.  
  1541.         if(!retval) retval = dswdir(t_fname,dir);
  1542.         
  1543.         /* Free the ACL */
  1544.         aclfree(dir->dacl); dir->dacl = NULL;
  1545.  
  1546.         /* if successfull say so (need to clean this up) */
  1547.         if(!retval)
  1548.             replyf(req,"SUCCESS",0);
  1549.         else replyf(req,"FAILURE",0);
  1550.         
  1551.         break;
  1552.         
  1553.         case DELETE_LINK: 
  1554.         dellnk_count++;
  1555.         t_num = 1;
  1556.         
  1557.         tmp = sscanf(command,"DELETE-LINK VLINK %s NUMBER %d",
  1558.                  t_name,&t_num);
  1559.         
  1560.         /* Log and return a better message */
  1561.         if(tmp < 1) {
  1562.             sendmf(req,"ERROR too few arguments",0);
  1563.             plog(L_DIR_PERR,client_host,client_id,"Too few arguments: %s",
  1564.              command, 0);
  1565.             return(PFAILURE);
  1566.         }
  1567.         
  1568.         /* Do we need a better log message */
  1569.         plog(L_DIR_UPDATE,client_host,client_id,"RM %s %s # %d",
  1570.              client_dir,t_name,t_num,0);
  1571.         
  1572.         retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
  1573.         if(retval == DSRFINFO_FORWARDED) goto dforwarded;
  1574.         
  1575.         /* If not a directory, say so */
  1576.         if(retval == DSRDIR_NOT_A_DIRECTORY) {
  1577.             sendmf(req,"NOT-A-DIRECTORY",0);
  1578.             plog(L_DIR_ERR, client_host, client_id, 
  1579.              "Invalid directory name: %s", client_dir,0);
  1580.             return(PFAILURE);
  1581.         }
  1582.         
  1583.         /* Need to find the link so we can check its ACL */
  1584.         clink = dir->links;
  1585.         while(clink) {
  1586.             if(strcmp(clink->name,t_name) == 0)
  1587.             break;
  1588.             clink = clink->next;
  1589.         }
  1590.         if(!clink) {
  1591.             clink = dir->ulinks;
  1592.             while(clink) {
  1593.             if(strcmp(clink->name,t_name) == 0)
  1594.                 break;
  1595.             clink = clink->next;
  1596.             }         
  1597.         }
  1598.         if(clink) wacl = clink->acl;
  1599.         else wacl = NULL;
  1600.  
  1601.         /* If not authorized, say so */
  1602.         if(!check_acl(dir->dacl,wacl,id,"d")) {
  1603.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  1604.             plog(L_AUTH_ERR,client_host,client_id,
  1605.              "Unauthorized DELETE-LINK: %s %s",client_dir,
  1606.              t_name,0); 
  1607.             /* Free the directory links */
  1608.             vllfree(dir->links); dir->links = NULL;
  1609.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1610.             aclfree(dir->dacl); dir->dacl = NULL;
  1611.             return(PFAILURE);
  1612.         }
  1613.  
  1614.         clink = vl_delete(dir->links,t_name,t_num);
  1615.         if(!perrno) dir->links = clink;
  1616.  
  1617.         else {
  1618.             clink = vl_delete(dir->ulinks,t_name,t_num);
  1619.             if(!perrno) dir->ulinks = clink;
  1620.         }
  1621.         
  1622.         if(perrno) {
  1623.             sendmf(req,"FAILURE NOT-FOUND FILE %s",t_name,0);
  1624.             plog(L_DIR_ERR,client_host,client_id,"Link not found: %s %s",
  1625.              client_dir, t_name,0);
  1626.             /* Free the directory links */
  1627.             vllfree(dir->links); dir->links = NULL;
  1628.             vllfree(dir->ulinks); dir->ulinks = NULL;
  1629.             aclfree(dir->dacl); dir->dacl = NULL;
  1630.             return(PFAILURE);
  1631.         }
  1632.         
  1633.         retval = dswdir(client_dir,dir);
  1634.         
  1635.         /* Free the directory links */
  1636.         vllfree(dir->links); dir->links = NULL;
  1637.         vllfree(dir->ulinks); dir->ulinks = NULL;
  1638.         aclfree(dir->dacl); dir->dacl = NULL;
  1639.         
  1640.         /* if successfull say so (need to clean this up) */
  1641.         if(!retval)
  1642.             replyf(req,"SUCCESS",0);
  1643.         else replyf(req,"FAILURE",0);
  1644.         
  1645.         break;
  1646. #endif
  1647.         
  1648.         case GET_OBJECT_INFO:    
  1649.         goi_count++;
  1650.         t_num = 0;
  1651.         item_count = 0;
  1652.         
  1653.         /* still have to read the remainder of the attributes */
  1654.         tmp = sscanf(command,"GET-OBJECT-INFO %s ID %s %s %*d %d",
  1655.                  t_name,t_ntype,t_fname,&t_num);
  1656.         
  1657.         /* Log and return a better message */
  1658.         if(tmp < 3) {
  1659.             sendmf(req,"ERROR wrong number of arguments",0);
  1660.             plog(L_DIR_PERR,client_host,client_id,"Too few arguments: %s", 
  1661.              command, 0);
  1662.             return(PFAILURE);
  1663.         }
  1664.         
  1665.         /* Do we need a better log message */
  1666.         plog(L_DIR_REQUEST, client_host, client_id, "GOI %s %s",
  1667.              t_name,t_fname,0);
  1668.         
  1669.         if(check_path(t_fname) == FALSE) {
  1670.             sendmf(req,"FAILURE NOT-AUTHORIZED",0);
  1671.             plog(L_AUTH_ERR,client_host,client_id,
  1672.              "Invalid directory name: %s",t_fname,0);
  1673.             return(PFAILURE);
  1674.         }
  1675.  
  1676.         clink = vlalloc();
  1677.         fi = pfalloc();
  1678.         
  1679.         clink->nametype = stcopyr(t_ntype,clink->nametype);
  1680.         clink->filename = stcopyr(t_fname,clink->filename);
  1681.         clink->f_magic_no = t_num;
  1682.         
  1683.         rsinfo_ret = dsrfinfo(clink->filename,clink->f_magic_no,fi);
  1684.         
  1685.         if(strcmp(t_name,"FORWARDING-POINTER") == 0) {
  1686.             if(rsinfo_ret == DSRFINFO_FORWARDED) {
  1687.             if(fl = check_fwd(fi->forward,clink->filename,
  1688.                       clink->f_magic_no)) {
  1689.                 replyf(req,"OBJECT-INFO FORWARDING-POINTER LINK L FP %s %s %s %s %s %d %d",
  1690.                    quote(clink->name),
  1691.                    fl->hosttype, fl->host,
  1692.                    fl->nametype, fl->filename,
  1693.                    fl->version,fl->f_magic_no,0);
  1694.                 item_count++;
  1695.             }
  1696.             }
  1697.             
  1698.             else if((clink->f_magic_no == 0) && (fi->f_magic_no != 0)) {
  1699.             replyf(req,"OBJECT-INFO FORWARDING-POINTER LINK L FP %s %s %s %s %s %d %d",
  1700.                    quote(clink->name),
  1701.                    clink->hosttype, hostwport,
  1702.                    clink->nametype, clink->filename,
  1703.                    clink->version,fi->f_magic_no,0);
  1704.             item_count++;
  1705.             }
  1706.         }
  1707.         else if(rsinfo_ret == DSRFINFO_FORWARDED) {
  1708.             fl = fi->forward; fi->forward = NULL;
  1709.             fp = check_fwd(fl,clink->filename,clink->f_magic_no);
  1710.             
  1711.             /* Free what we don't need */
  1712.             pffree(fi); fi = NULL;
  1713.             
  1714.             /* Got to location to return forwarded error */
  1715.             goto forwarded;
  1716.         }
  1717.         else if(strcmp(t_name,"ACCESS-METHODS") == 0) {
  1718.             oldform_count += 100000; /* Really old count is shifted */
  1719.             plog(L_DIR_PWARN,client_host,client_id,
  1720.              "Old format GOI AM",0);
  1721. #ifdef NFS_EXPORT
  1722.             amarg = check_nfs(t_fname,client_host);
  1723.             if(amarg) {
  1724.             replyf(req,"OBJECT-INFO ACCESS-METHOD NFS %s",
  1725.                    amarg, 0);
  1726.             item_count++;
  1727.             }
  1728. #endif NFS_EXPORT
  1729.             
  1730. #ifdef AFSDIRECTORY
  1731.             if(*afsdir && (sindex(clink->filename,afsdir) == 
  1732.                     clink->filename)) {
  1733.             suffix = clink->filename + strlen(afsdir);
  1734.             replyf(req,"OBJECT-INFO ACCESS-METHOD AFS %s",
  1735.                    suffix,0);
  1736.             item_count++;
  1737.             }
  1738. #endif AFSDIRECTORY
  1739.  
  1740. #ifdef AFTPDIRECTORY
  1741.             if(*aftpdir && (sindex(clink->filename,aftpdir) == 
  1742.                     clink->filename)) {
  1743.             suffix = clink->filename + strlen(aftpdir);
  1744.             replyf(req,"OBJECT-INFO ACCESS-METHOD ANONYMOUS-FTP %s %s", 
  1745.                    suffix,"BINARY",0);
  1746.             item_count++;
  1747.             
  1748.             }
  1749. #endif AFTPDIRECTORY
  1750.  
  1751.         }
  1752.         else if(strcmp(t_name,"ACCESS-METHOD") == 0) {
  1753.             
  1754. #ifdef NFS_EXPORT
  1755.             amarg = check_nfs(t_fname,client_host);
  1756.             if(amarg) {
  1757.             replyf(req,"OBJECT-INFO ACCESS-METHOD ASCII NFS %s",
  1758.                    amarg,0);
  1759.             item_count++;
  1760.             }
  1761. #endif NFS_EXPORT
  1762.             
  1763. #ifdef AFSDIRECTORY
  1764.             if(*afsdir && (sindex(clink->filename,afsdir) == 
  1765.                    clink->filename)) {
  1766.             suffix = clink->filename + strlen(afsdir);
  1767.             replyf(req,"OBJECT-INFO ACCESS-METHOD ASCII AFS %s",
  1768.                    suffix,0);
  1769.             item_count++;
  1770.             }
  1771. #endif AFSDIRECTORY
  1772.  
  1773. #ifdef AFTPDIRECTORY
  1774.             /* Find the real name of the file and use it */
  1775.             /* To check for AFTP access                  */
  1776. /*            rnl = readlink(clink->filename,rname,MAXPATHLEN); */
  1777. /*             if(rnl >= 0) *(rname+rnl) = '\0';                 */
  1778.  
  1779.             if(*aftpdir && (sindex(clink->filename,aftpdir) == 
  1780.                     clink->filename)) {
  1781.             suffix = clink->filename + strlen(aftpdir);
  1782.             replyf(req,"OBJECT-INFO ACCESS-METHOD ASCII ANONYMOUS-FTP %s %s", 
  1783.                    suffix,"BINARY",0);
  1784.             item_count++;
  1785.             }
  1786. #endif AFTPDIRECTORY
  1787.         }
  1788.         else {
  1789.             /* Here we must check the file info, look for matching */
  1790.             /* attributes and return them                          */
  1791.             if(rsinfo_ret <= 0) {
  1792.             ca = fi->attributes;
  1793.             while(ca) {
  1794.                 if((strcmp(t_name,ca->aname) == 0) || 
  1795.                    (strcmp(t_name,"ALL") == 0)) {
  1796.                 replyf(req,"OBJECT-INFO %s %s %s",
  1797.                        ca->aname,ca->avtype,ca->value.ascii,0);
  1798.                 item_count++;
  1799.                 }
  1800.                 ca = ca->next;
  1801.             }
  1802.             }
  1803.         }
  1804.         
  1805.         /* If none, match, say so */
  1806.         if(!item_count)
  1807.             replyf(req,"NONE-FOUND",0);
  1808.         
  1809.         pffree(fi); fi = NULL;
  1810.         vlfree(clink);
  1811.         break;
  1812.         
  1813.         case RESTART: 
  1814.         plog(L_STATUS,client_host,client_id,
  1815.              "Server restarted (restart message received)",0);
  1816.         sendmf(req,"RESTARTING",0);
  1817.         restart_server(0,NULL);
  1818.         break;
  1819.  
  1820. #ifdef DIE
  1821.         case TERMINATE: 
  1822.         plog(L_STATUS,client_host,client_id,
  1823.              "Server killed (terminate message received)",0);
  1824.         sendmf(req,"TERMINATING",0);
  1825.         log_stats();
  1826.         exit(0);
  1827. #endif DIE
  1828.         
  1829.         default: 
  1830.         plog(L_DIR_PERR,client_host,client_id,
  1831.              "Unknown message: %s",command);
  1832.         replyf(req,"UNIMPLEMENTED %s",command,0);
  1833.  
  1834.         }
  1835.         
  1836.         get_token(command,'\n');       /* Defined in pprot.h */
  1837.         continue;
  1838.         
  1839.     dforwarded:
  1840.         fl = dir->f_info->forward; dir->f_info->forward = NULL;
  1841.         fp = check_fwd(fl,client_dir,dir_magic_no);
  1842.         
  1843.         /* Free what we don't need */
  1844.         vllfree(dir->links); dir->links = NULL;
  1845.         vllfree(dir->ulinks); dir->ulinks = NULL;
  1846.         aclfree(dir->dacl); dir->dacl = NULL;
  1847.         pffree(dir->f_info);
  1848.         
  1849.     forwarded:
  1850.         
  1851.         if(fp) {
  1852.         replyf(req,"FORWARDED %s %s %s %s %d %d",
  1853.                fp->hosttype,fp->host,fp->nametype,fp->filename,
  1854.                fp->version,fp->f_magic_no,0);
  1855.         }
  1856.         else replyf(req,"FORWARDED",0);
  1857.         vllfree(fl);
  1858.         
  1859.         get_token(command,'\n');       /* Defined in pprot.h */
  1860.     }
  1861.     sendm(req,NULL);
  1862.     return(PSUCCESS);
  1863.     }
  1864.  
  1865.     /*
  1866.      * cmd_lookup - lookup the command name and return integer
  1867.      *
  1868.      *    CMD_LOOKUP takes a pointer to a string containing a command.
  1869.      *    It then looks up the first word found in the string and
  1870.      *    returns an int that can be used in a switch to dispatch
  1871.      *    to the correct routines.
  1872.      *
  1873.      *    This has been optimzed for the swerver side of the VFS protocol.
  1874.      */
  1875.     static cmd_lookup(cmd)
  1876.     char    *cmd;
  1877.     {
  1878.     switch(*cmd) {
  1879.     case 'A':
  1880.         if(!strncmp(cmd,"AUTHENTICATOR",13))
  1881.         return(AUTHENTICATOR);
  1882.         else return(UNIMPLEMENTED);
  1883. #ifndef PSRV_READ_ONLY
  1884.     case 'C':
  1885.         if(!strncmp(cmd,"CREATE-OBJECT",11))
  1886.         return(CREATE_OBJECT);
  1887.         else if(!strncmp(cmd,"CREATE-LINK",11))
  1888.         return(CREATE_LINK);
  1889.         else if(!strncmp(cmd,"CREATE-DIRECTORY",16))
  1890.         return(CREATE_DIRECTORY);
  1891.         else return(UNIMPLEMENTED);
  1892. #endif
  1893.     case 'D':
  1894.         if(!strncmp(cmd,"DELETE-LINK",11))
  1895. #ifndef PSRV_READ_ONLY
  1896.         return(DELETE_LINK);
  1897. #else
  1898.             return(UNIMPLEMENTED);
  1899. #endif
  1900.         else if(!strncmp(cmd,"DIRECTORY",9))
  1901.         return(DIRECTORY);
  1902.         else return(UNIMPLEMENTED);
  1903. #ifndef PSRV_READ_ONLY
  1904.     case 'E':
  1905.         if(!strncmp(cmd,"EDIT-OBJECT-INFO",14))
  1906.         return(EDIT_OBJECT_INFO);
  1907.         else return(UNIMPLEMENTED);
  1908. #endif
  1909.     case 'G':
  1910.         if(!strncmp(cmd,"GET-OBJECT-INFO",13))
  1911.         return(GET_OBJECT_INFO);
  1912.         else return(UNIMPLEMENTED);
  1913.     case 'L':
  1914.         if(!strncmp(cmd,"LIST-ACL",8))
  1915.         return(LIST_ACL);
  1916.         else if(!strncmp(cmd,"LIST",4))
  1917.         return(LIST);
  1918.         else return(UNIMPLEMENTED);
  1919. #ifndef PSRV_READ_ONLY
  1920.     case 'M':
  1921.         if(!strncmp(cmd,"MODIFY-ACL",10))
  1922.         return(MODIFY_ACL);
  1923.         else if(!strncmp(cmd,"MODIFY-LINK",11))
  1924.         return(MODIFY_LINK);
  1925.         else return(UNIMPLEMENTED);
  1926. #endif
  1927.     case 'P':
  1928.         if(!strncmp(cmd,"PACKET",1))
  1929.         return(PACKET);
  1930.         else return(UNIMPLEMENTED);
  1931.     case 'R':
  1932.         if(!strncmp(cmd,"RESTART",7))
  1933.         return(RESTART);
  1934.         else return(UNIMPLEMENTED);
  1935.     case 'S':
  1936.         if(!strncmp(cmd,"STATUS",6))
  1937.         return(STATUS);
  1938.         else return(UNIMPLEMENTED);
  1939.     case 'T':
  1940.         if(!strncmp(cmd,"TERMINATE",9))
  1941.         return(TERMINATE);
  1942.         else return(UNIMPLEMENTED);
  1943. #ifndef PSRV_READ_ONLY
  1944.     case 'U':
  1945.         if(!strncmp(cmd,"UPDATE",6))
  1946.         return(UPDATE);
  1947.         else return(UNIMPLEMENTED);
  1948. #endif
  1949.     case 'V':
  1950.         if(!strncmp(cmd,"VERSION",7))
  1951.         return(VERSION);
  1952.         else return(UNIMPLEMENTED);
  1953.     default:
  1954.         return(UNIMPLEMENTED);
  1955.     }
  1956.     }
  1957.  
  1958. SIGNAL_RET_TYPE term_sig()
  1959. {
  1960.     char        qlstring[30];
  1961.  
  1962.     if(pQlen > 0) sprintf(qlstring," [%d pending]",pQlen);
  1963.     else *qlstring = '\0';
  1964.  
  1965.     plog(L_STATUS,NULL,NULL,"Server killed (terminate signal received)%s",qlstring,0);
  1966.     log_stats();
  1967.     exit(0);
  1968. }
  1969.  
  1970. SIGNAL_RET_TYPE trap_error(sig, code, scp)
  1971.     int            sig;
  1972.     int            code;
  1973.     struct  sigcontext    *scp;
  1974. {
  1975.     char        estring[400];
  1976.  
  1977.     if(pQlen > 0) sprintf(estring," [%d pending]",pQlen);
  1978.     else *estring = '\0';
  1979.  
  1980.     plog(L_FAILURE,NULL,NULL,"Failure - Recovering from error at address 0x%x (%d,%d)%s",scp->sc_pc,sig,code,estring,0);
  1981. #ifdef DEBUG
  1982.     plog(L_DIR_ERR,NULL,NULL,"Last request was: %s",last_request,0);
  1983.     sprintf(estring,"Signal(%d,%d) at 0x%x\n%.300s", sig, code,
  1984.         scp->sc_pc, last_request);
  1985. #else
  1986.     sprintf(estring,"Signal(%d,%d) at 0x%x", sig, code, scp->sc_pc);
  1987. #endif DEBUG
  1988.  
  1989.     restart_server(++fault_count,estring);
  1990.     exit(1);
  1991. }
  1992.  
  1993. /*
  1994.  * restart server restarts the server by calling exec.  Before
  1995.  * restarting, it logs the current statisitcs which would otherwise
  1996.  * be lost.
  1997.  */
  1998. restart_server(fcount,estring)
  1999.     int            fcount;        /* Failure count */
  2000.     char        *estring;    /* Error string  */
  2001. {
  2002.     char        dirsrv_b[MAXPATHLEN];
  2003.     char        fault_flag[30];
  2004.     char        error_flag[500];
  2005.     int            f;
  2006.  
  2007.     /* Log statistics before we forget them on restart */
  2008.     log_stats();
  2009.  
  2010.     /* Close all files except stdin, stdout, and stderr */
  2011.     /* which should still be /dev/null, and in_port     */
  2012.     /* which we might not be able to reopen             */
  2013.     close_plog();
  2014.     for (f = 3; f < OPEN_MAX; f++) {
  2015.     if(f != in_port) (void) close(f);
  2016.     }
  2017.  
  2018.     sprintf(dirsrv_b,"%s/dirsrv",P_BINARIES);
  2019.     if(estring) sprintf(error_flag,"-E%-0.497s",estring);
  2020.     if(fcount) sprintf(fault_flag,"-F%d",fcount);
  2021.  
  2022.     /* Reinstate the signal that caused the fault */
  2023.     sigsetmask(0);
  2024.  
  2025.     /* Restart the server specifying the appropriate flags */
  2026.     if((fcount == 0) && !estring)
  2027.     execl(dirsrv_b,"dirsrv",in_parg,root,shadow,pfsdat,aftpdir,
  2028.           afsdir,hostname,0);
  2029.     else if((fcount != 0) && estring) 
  2030.     execl(dirsrv_b,"dirsrv",in_parg,fault_flag,error_flag,root,shadow,
  2031.           pfsdat,aftpdir,afsdir,hostname,0);
  2032.     else execl(dirsrv_b,"dirsrv",in_parg,(fcount ? fault_flag : error_flag),
  2033.            root,shadow,pfsdat,aftpdir,afsdir,hostname,0);
  2034.  
  2035.     /* If we get here, the exec failed */
  2036.     plog(L_FAILURE,NULL,NULL,"***Failure - Couldn't restart server - exiting***",0);
  2037.     exit(1);
  2038. }
  2039.  
  2040. /*
  2041.  * setup_disc 
  2042.  *
  2043.  *      disconnect all descriptors, remove ourself from the process
  2044.  *      group that spawned us and set signal handlers.
  2045.  */
  2046. setup_disc()
  2047.     {
  2048.  
  2049.     int     s;
  2050.  
  2051.     for (s = 0; s < 3; s++) {
  2052.         (void) close(s);
  2053.     }
  2054.  
  2055.     (void) open("/dev/null", 0, 0);
  2056.     (void) dup2(0, 1);
  2057.     (void) dup2(0, 2);
  2058.  
  2059. #ifdef SETSID
  2060.      setsid();
  2061. #else
  2062.       s = open("/dev/tty", 2, 0);
  2063.   
  2064.       if (s >= 0) {
  2065.           ioctl(s, TIOCNOTTY, (struct sgttyb *) 0);
  2066.           (void) close(s);
  2067.       }
  2068. #endif
  2069.  
  2070.     (void) chdir(P_RUNDIR);
  2071.  
  2072.     signal(SIGHUP,term_sig);
  2073.     signal(SIGINT,term_sig);
  2074.     signal(SIGTERM,term_sig);
  2075.     signal(SIGQUIT,term_sig);
  2076.  
  2077.     signal(SIGILL,trap_error);
  2078.     signal(SIGIOT,trap_error);
  2079.     signal(SIGEMT,trap_error);
  2080.     signal(SIGFPE,trap_error);
  2081.     signal(SIGBUS,trap_error);
  2082.     signal(SIGSEGV,trap_error);
  2083.     signal(SIGSYS,trap_error);
  2084.  
  2085.     return;
  2086.     }
  2087.  
  2088. static
  2089. log_stats()
  2090.   {
  2091.     plog(L_STATS,NULL,NULL,"Stats: %d List, %d GOI, %d LACL",
  2092.      list_count,goi_count,lacl_count,0);
  2093.     plog(L_STATS,NULL,NULL,"       %d CL, %d CD, %d CO, %d DL",
  2094.      crlnk_count,crdir_count,crobj_count,dellnk_count,0);
  2095.     plog(L_STATS,NULL,NULL,"       %d ML, %d EOI, %d MACL, %d Upd", 
  2096.      modl_count,eoi_count,macl_count,upddir_count,0);
  2097.     if(oldform_count) plog(L_STATS,NULL,NULL,"       %d Total, %d Old format", 
  2098.                req_count, oldform_count, 0);
  2099.     else plog(L_STATS,NULL,NULL,"       %d Total", req_count,0);
  2100.  
  2101.   }
  2102.  
  2103.  
  2104. static
  2105. check_path(path)
  2106.     char    *path;
  2107.     {
  2108.     if(*db_prefix && (sindex(path,db_prefix) == path)) return(TRUE);
  2109. #ifdef NODOTDOT
  2110.     if(wcmatch(path,"*..*")) return(FALSE);
  2111. #endif
  2112.     if(sindex(path,pfsdat) == path) return(TRUE);
  2113.     if(*root && (sindex(path,root) == path)) return(TRUE);
  2114.     if(*aftpdir && (sindex(path,aftpdir) == path)) return(TRUE);
  2115.     if(*afsdir && (sindex(path,afsdir) == path)) return(TRUE);
  2116.     return(FALSE);
  2117.     }
  2118.  
  2119.